package scheme;
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Properties;
import accessstruct.Tool;
import algorithms.AttrTrans;
import util.ConfigFileName;
/**
 * AA类
 * 主要功能：
 * 1.AA初始化
 * 2.用户属性密钥生成
 * 3.属性认证密钥生成
 */
public class AA {
    /**
     * AA初始化步骤--生成AA的公钥和私钥
     * @param config 配置信息
     * @param aid   aid
     * @param attOfAA   管理的属性列表
     * @return
     */
    public static long setup(ConfigFileName config,int aid , String[] attOfAA) {
        /*********************************************获取公共参数*******************************************************/
        //准备工作获取公参
        Pairing bp = PairingFactory.getPairing(config.getPairingParametersFileName());
        Properties AAskProp = Tool.loadPropFromFile(config.getAASKFileName());
        Properties AApkProp = Tool.loadPropFromFile(config.getAAPKFileName());
        Properties GPProp = Tool.loadPropFromFile(config.getGPFileName());
        //获取g
        String gString = GPProp.getProperty("g");
        Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
        /************************************************计算私钥公钥*****************************************************/
        //选取AA私钥和公钥
        long startTime = System.currentTimeMillis();
        //AA私钥
        Element alpha = bp.getZr().newRandomElement().getImmutable();
        Element beta  = bp.getZr().newRandomElement().getImmutable();
        //AA公钥
        Element egg_beta = bp.pairing(g,g).powZn(beta).getImmutable();
        Element g_alpha = g.powZn(alpha).getImmutable();

        long endTime = System.currentTimeMillis();
        //生成系统公钥和私钥并存入prop文件之中
        //存储私钥
        AAskProp.setProperty("alpha-"+aid, Base64.getEncoder().withoutPadding().encodeToString(alpha.toBytes()));
        AAskProp.setProperty("beta-"+aid, Base64.getEncoder().withoutPadding().encodeToString(beta.toBytes()));
        //存储公钥
        AApkProp.setProperty("egg_beta-"+aid, Base64.getEncoder().withoutPadding().encodeToString(egg_beta.toBytes()));
        AApkProp.setProperty("g_alpha-"+aid, Base64.getEncoder().withoutPadding().encodeToString(g_alpha.toBytes()));

        Tool.storePropToFile(AAskProp, config.getAASKFileName());
        Tool.storePropToFile(AApkProp, config.getAAPKFileName());
        System.out.println("AA "+aid+ " 完成初始化" );
        System.out.println("+++AA-"+aid+" 初始化时间: "+(endTime - startTime)+"  ms");
        return endTime - startTime;
    }
    /**
     * AA密钥生成--生成用户的属性私钥
     */
    public static long keygen(ConfigFileName config , String userID, String[] userAttList, int aid) throws NoSuchAlgorithmException {
        /********************************************获取公共参数和AA私钥*************************************************/
        //准备工作
        Pairing bp = PairingFactory.getPairing(config.getPairingParametersFileName());
        //读取系统公共参数GP
        Properties GPProp = Tool.loadPropFromFile(config.getGPFileName());
        String gString = GPProp.getProperty("g");
        Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
        String wString = GPProp.getProperty("w");//
        Element w = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(wString)).getImmutable();
        String vString = GPProp.getProperty("v");//
        Element v = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(vString)).getImmutable();

        //读取AA公钥 g^alpha
        Properties AApkProp = Tool.loadPropFromFile(config.getAAPKFileName());
        String g_alphaString = AApkProp.getProperty("g_alpha-"+aid);
        Element g_alpha = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(g_alphaString)).getImmutable();

        //读取每个AA私钥AA_SK_alpha_aid  AA_SK_beta_aid
        Properties AAskProp = Tool.loadPropFromFile(config.getAASKFileName());
        String alphaString = AAskProp.getProperty("alpha-"+aid);
        Element alpha = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(alphaString)).getImmutable();
        String betaString = AAskProp.getProperty("beta-"+aid);
        Element beta = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(betaString)).getImmutable();

        //加载用户密钥存储工具
        Properties UserSkProp = Tool.loadPropFromFile(config.getUserSKFileName());
        /****************************************************生成用户属性密钥********************************************/
        //开始申城属性密钥
        long startTime = System.currentTimeMillis();
        //AA随机选取r_aid
        Element r_aid = bp.getZr().newRandomElement().getImmutable();
        //生成属性密钥
        Element K = g.powZn(beta.mul(alpha.invert())).mul(w.powZn(r_aid)).getImmutable();
        //发送给CA的部分
        Element L_0 = g.powZn(r_aid).getImmutable();
        Element L_1 = g_alpha.powZn(r_aid).getImmutable();


        UserSkProp.setProperty("r-"+aid, Base64.getEncoder().withoutPadding().encodeToString(r_aid.toBytes()));//
        //开始存储用户属性密钥
        UserSkProp.setProperty("K-"+aid+"-"+userID, Base64.getEncoder().withoutPadding().encodeToString(K.toBytes()));
        UserSkProp.setProperty("L0-"+aid+"-"+userID, Base64.getEncoder().withoutPadding().encodeToString(L_0.toBytes()));
        UserSkProp.setProperty("L1-"+aid+"-"+userID, Base64.getEncoder().withoutPadding().encodeToString(L_1.toBytes()));

        for (String att :userAttList) {
            //属性密钥
            byte[] attHash = Tool.sha1(att);
            Element Si = bp.getZr().newElementFromHash(attHash, 0, attHash.length).getImmutable();
            Element K_att = g.powZn(r_aid).powZn(Si).mul(v.powZn(alpha).powZn(r_aid)).getImmutable();

            //存储属性密钥
            UserSkProp.setProperty("K"+att+"-"+aid+"-"+userID, Base64.getEncoder().withoutPadding().encodeToString(K_att.toBytes()));
        }
        long endTime = System.currentTimeMillis();
        Tool.storePropToFile(UserSkProp, config.getUserSKFileName());
        System.out.println("+++AA-"+aid+" 属性密钥生成时间: "+(endTime - startTime)+"  ms");
        return endTime - startTime;
    }

    /**
     * 生成用户属性认证密钥这个是给用户生成的，但是不发给用户，
     */
    public static void AUK_Gen(ConfigFileName config , String userId, String[] userAttList, int aid) throws NoSuchAlgorithmException {
        /********************************************获取公共参数********************************************************/
        //准备工作获取公参
        Pairing bp = PairingFactory.getPairing(config.getPairingParametersFileName());
        Properties AAskProp = Tool.loadPropFromFile(config.getAASKFileName());
        Properties GPProp = Tool.loadPropFromFile(config.getGPFileName());
        Properties CSPUAKProp = Tool.loadPropFromFile(config.getCSPUAKFileName());

        //H（uid）
        Element H_uid = bp.getG1().newElementFromHash(userId.getBytes(), 0, userId.getBytes().length).getImmutable();

        //获取g
        String gString = GPProp.getProperty("g");
        Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();

        //用来保存属性转换密钥给CSP其实并不需要这一步，因为都存在properties下了
        Element[] UAKList= new Element[userAttList.length];
        /**************************************************************************************************************/
        long startTime = System.currentTimeMillis();
        //获取AA属性私钥"AttrSK_eta_"+i+"_"+aid
        for(int i = 0;i<userAttList.length;i++){
            String etaString = AAskProp.getProperty("eta_"+userAttList[i]);
            Element eta_x = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(etaString)).getImmutable();
            String gammaString = AAskProp.getProperty("gamma_"+userAttList[i]);
            Element gamma_x = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(gammaString)).getImmutable();
            Element UAK_i_uid = g.powZn(eta_x).mul(H_uid.powZn(gamma_x)).getImmutable();
            CSPUAKProp.setProperty("UAK_"+userAttList[i]+"_"+userId, Base64.getEncoder().withoutPadding().encodeToString(UAK_i_uid.toBytes()));
            UAKList[i] = UAK_i_uid;
        }
        long endTime = System.currentTimeMillis();
        Tool.storePropToFile(CSPUAKProp,config.getCSPUAKFileName());
        CSP.saveUserAUK(H_uid,UAKList);
        System.out.println("AA-"+aid+"-AUK生成时间:  "+(endTime - startTime)+"  ms");
    }
}

